package io.github.talelin.latticy.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.github.talelin.autoconfigure.exception.NotFoundException;
import io.github.talelin.autoconfigure.exception.ParameterException;
import io.github.talelin.latticy.mapper.AcceptMapper;
import io.github.talelin.latticy.mapper.MaintenanceMapper;
import io.github.talelin.latticy.mapper.SerialNumberMapper;
import io.github.talelin.latticy.model.AcceptDO;
import io.github.talelin.latticy.model.SerialNumberDO;
import io.github.talelin.latticy.service.MaintenanceService;
import io.github.talelin.latticy.dto.maintenance.CreateOrUpdateMaintenanceDTO;
import io.github.talelin.latticy.model.MaintenanceDO;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import io.github.talelin.latticy.utils.DateUtil;
import io.github.talelin.latticy.vo.MaintenanceVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

/**
 * @author vvboy
 */
@Service
public class MaintenanceServiceImpl implements MaintenanceService {

    @Autowired
    private MaintenanceMapper maintenanceMapper;
    @Autowired
    private AcceptMapper acceptMapper;

    @Autowired
    private SerialNumberMapper serialNumberMapper;

    private final ReentrantLock lock = new ReentrantLock();

    @Override
    public boolean createMaintenance(CreateOrUpdateMaintenanceDTO validator) {

        String orderNumber = validator.getOrderNumber();
        Long l = maintenanceMapper.selectCount(Wrappers.<MaintenanceDO>lambdaQuery()
                .eq(MaintenanceDO::getOrderNumber, orderNumber));
        if(l>0){
            throw new ParameterException(10401);
        }

        MaintenanceDO maintenance = new MaintenanceDO();


        BeanUtils.copyProperties(validator, maintenance);





        List<String> shelf = validator.getShelf();
        if (CollectionUtils.isEmpty(shelf) || shelf.size() != 2) {
            throw new ParameterException("所修项目保用期时间格式错误");
        }
        Date startDate = DateUtil.stringConvertDate(shelf.get(0));
        Date endDate = DateUtil.stringConvertDate(shelf.get(1));
        if (startDate == null || endDate == null) {
            throw new ParameterException("所修项目保用期时间格式错误");
        }
        QueryWrapper<AcceptDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_number",validator.getOrderNumber());
        List<AcceptDO> query = acceptMapper.selectList(queryWrapper);


        LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
        LocalDateTime todayEnd = todayStart.plusDays(1).minusNanos(1);
        List<SerialNumberDO> serialNumberDOList = serialNumberMapper.selectList(Wrappers.<SerialNumberDO>lambdaQuery()
                .eq(SerialNumberDO::getName, "maintenance")
                .orderByDesc(SerialNumberDO::getCreateTime));
        Integer index = 0;
        if (CollectionUtils.isEmpty(serialNumberDOList)) {
            SerialNumberDO serialNumberDO = new SerialNumberDO();
            serialNumberDO.setName("maintenance");
            serialNumberDO.setNumber(0);
            serialNumberMapper.insert(serialNumberDO);
        }

        // 生成工单
        lock.lock();
        try {
            SerialNumberDO serialNumberDO = serialNumberDOList.get(0);
            // 只有当天 且 不是0的情况，number才会算数，否则都是0
            if (cn.hutool.core.date.DateUtil.isSameDay(new Date(), serialNumberDO.getUpdateTime())
                    && serialNumberDO.getNumber() != 0) {
                index = serialNumberDO.getNumber();
            }
            index += 1;
            String seq = cn.hutool.core.date.DateUtil.format(new Date(), "yyyyMMdd");
            seq = seq + (index <= 999 ? String.format("%04d", index) : String.valueOf(index));
            serialNumberDO.setNumber(index);
            serialNumberDO.setUpdateTime(new Date());
            serialNumberMapper.updateById(serialNumberDO);


            if(query==null|| query.size() == 0){
                throw new ParameterException(10400);
            }else {
                AcceptDO acceptDO = query.get(0);
                acceptDO.setStatus("1");
                acceptMapper.updateById(acceptDO);
            }
            maintenance.setShelfStart(startDate);
            maintenance.setShelfEnd(endDate);

            // 设置工单
            maintenance.setWorkNumber(seq);
            return maintenanceMapper.insert(maintenance) > 0;
        } finally {
            lock.unlock();
        }
    }


    @Override
    public boolean updateMaintenance(MaintenanceDO maintenance, CreateOrUpdateMaintenanceDTO validator) {
        BeanUtils.copyProperties(validator, maintenance);

        maintenance.setOrderNumber(null);

        List<String> shelf = validator.getShelf();
        if (!CollectionUtils.isEmpty(shelf) && shelf.size() == 2) {
            Date startDate = DateUtil.stringConvertDate(shelf.get(0));
            Date endDate = DateUtil.stringConvertDate(shelf.get(1));
            if (startDate == null || endDate == null) {
                throw new ParameterException("所修项目保用期时间格式错误");
            }
            maintenance.setShelfStart(startDate);
            maintenance.setShelfEnd(endDate);
        }

        return maintenanceMapper.updateById(maintenance) > 0;
    }

    @Override
    public MaintenanceDO getById(Integer id) {
        return maintenanceMapper.selectById(id);
    }

    @Override
    public MaintenanceVo getByIdVo(Integer id) {
        MaintenanceDO maintenanceDO = maintenanceMapper.selectById(id);
        MaintenanceVo maintenanceVo = new MaintenanceVo();
        BeanUtils.copyProperties(maintenanceDO, maintenanceVo);

        Date shelfStart = maintenanceDO.getShelfStart();
        Date shelfEnd = maintenanceDO.getShelfEnd();
        if (shelfStart != null && shelfEnd != null) {
            ArrayList<String> dates = new ArrayList<>();
            dates.add(DateUtil.DateConvertString(shelfStart));
            dates.add(DateUtil.DateConvertString(shelfEnd));
            maintenanceVo.setShelf(dates);
        }

        return maintenanceVo;
    }

    @Override
    public List<MaintenanceDO> findAll() {
        List<MaintenanceDO> maintenanceDOS = maintenanceMapper.selectList(null);
        for(MaintenanceDO maintenanceDO :maintenanceDOS){
            maintenanceDO.setShelfStartString(cn.hutool.core.date.DateUtil.format(maintenanceDO.getShelfStart(),"yyyy-MM-dd"));
            maintenanceDO.setShelfEndString(cn.hutool.core.date.DateUtil.format(maintenanceDO.getShelfEnd(),"yyyy-MM-dd"));
        }
        return maintenanceDOS;
    }

    @Override
    public boolean deleteById(Integer id) {
        return maintenanceMapper.deleteById(id) > 0;
    }

    @Override
    public List<String> statCurMonth() {
        List<Integer> resInt = new ArrayList<>();
        int monthDays = cn.hutool.core.date.DateUtil.lengthOfMonth(cn.hutool.core.date.DateUtil.thisMonth() + 1, cn.hutool.core.date.DateUtil.isLeapYear(cn.hutool.core.date.DateUtil.thisYear()));
        for (int i = 0; i < monthDays; i++) {
            resInt.add(0);
        }

        List<MaintenanceDO> maintenanceDOS = maintenanceMapper.selectList(Wrappers
                .<MaintenanceDO>lambdaQuery()
                .between(MaintenanceDO::getCreateTime,
                        cn.hutool.core.date.DateUtil.beginOfMonth(new Date()),
                        cn.hutool.core.date.DateUtil.endOfMonth(new Date())));

        for (MaintenanceDO maintenanceDO : maintenanceDOS) {
            Date createTime = maintenanceDO.getCreateTime();
            int i = cn.hutool.core.date.DateUtil.dayOfMonth(createTime);
            resInt.set(i - 1, resInt.get(i - 1) + 1);
        }
        return resInt.stream().map(String::valueOf).collect(Collectors.toList());
    }

    @Override
    public Integer curMonthAcceptCount() {
        List<MaintenanceDO> maintenanceDOS = maintenanceMapper.selectList(Wrappers
                .<MaintenanceDO>lambdaQuery()
                .between(MaintenanceDO::getCreateTime,
                        cn.hutool.core.date.DateUtil.beginOfMonth(new Date()),
                        cn.hutool.core.date.DateUtil.endOfMonth(new Date())));
        return maintenanceDOS.size();
    }

}
